<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>8-给drag加上自定义事件.html</title>
    <style>
      #box {
        position: absolute;
        left: 0;
        top: 0;
        width: 100px;
        height: 100px;
        background: red;
        cursor: pointer;
      }
      .selectBox {
        position: fixed;
        border: 1px solid #06c0fd;
        background-color: rgba(6, 192, 255, 0.3);
      }
    </style>
  </head>
  <body>
    <div id="box"></div>
    <script src="js/event.js"></script>
    <script>
      class Drag extends Event {
        constructor(el) {
          super();
          this.el = el;
          this.startMouse = {}; // 按下时，鼠标坐标
          let move = (e) => {
            this.move(e);
          };
          this.el.addEventListener("mousedown", (e) => {
            this.start(e);
            document.addEventListener("mousemove", move);
            document.addEventListener(
              "mouseup",
              () => {
                this.end(e);
                document.removeEventListener("mousemove", move);
              },
              { once: true }
            );
          });
        }
        start(e) {
          /*
           * 拖拽：获取按下时元素坐标
           * 框选：创建元素用于画框
           */
          this.startMouse = {
            x: e.clientX,
            y: e.clientY,
          };
          this.dispatch("dragstart", e);
        }
        move(e) {
          /*
           * 拖拽：用按下时元素坐标+差值，计算当前元素的坐标
           * 框选：计算框的宽、高、left、top
           */
          let nowMouse = {
            x: e.clientX,
            y: e.clientY,
          };
          let dis = {
            x: nowMouse.x - this.startMouse.x,
            y: nowMouse.y - this.startMouse.y,
          };
          this.dispatch("dragmove", e, dis, nowMouse);
        }
        end(e) {
          /*
           * 拖拽：不作处理
           * 框选：移除框
           */
          this.dispatch("dragend", e);
        }
      }

      // 拖拽
      let box = document.querySelector("#box");
      let boxDrag = new Drag(box);

      let startOffset = {}; // 按下时，元素坐标
      boxDrag.on("dragstart", (e) => {
        console.log("开始拖拽时执行", e);
        startOffset = {
          x: parseFloat(getComputedStyle(box)["left"]),
          y: parseFloat(getComputedStyle(box)["top"]),
        };
        e.stopPropagation();
      });
      boxDrag.on("dragmove", (e, dis, now) => {
        console.log("拖拽中执行", e, dis, now);
        let nowOffset = {
          x: dis.x + startOffset.x,
          y: dis.y + startOffset.y,
        };
        box.style.left = nowOffset.x + "px";
        box.style.top = nowOffset.y + "px";
      });
      console.log(boxDrag);

      // 框选
      let selectDrag = new Drag(document);
      let select = null; // 记录元素
      selectDrag.on("dragstart", (e) => {
        start = {
          x: e.clientX,
          y: e.clientY,
        };
        select = document.createElement("div");
        select.className = "selectBox";
        document.body.appendChild(select);
        e.stopPropagation();
      });
      selectDrag.on("dragmove", (e, dis, now) => {
        // 框的宽度：两个坐标点的横向差值
        select.style.width = Math.abs(dis.x) + "px";
        // 框的高度：两个坐标点的纵向差值
        select.style.height = Math.abs(dis.y) + "px";
        // 框的left：两个坐标点靠近左侧的横坐标(较小的值)
        select.style.left = Math.min(now.x, selectDrag.startMouse.x) + "px";
        // 框的top：两个坐标点靠近上方的纵坐标(较小的值)
        select.style.top = Math.min(now.y, selectDrag.startMouse.y) + "px";
      });
      selectDrag.on("dragend", (e) => {
        select.remove();
      });
    </script>
  </body>
</html>
